package com.chat.controller;

import com.chat.model.Startup;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.converter.BeanOutputConverter;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.Map;

/**
 * @program: springboot3-demos
 * @description:
 * @author: Reagan Li
 * @create: 2024-04-26 10:14
 **/

@RestController
@RequestMapping("/openai")
public class ChatController {

    @Autowired
    private OpenAiChatModel openAiChatModel;

    @GetMapping(value = "/stream")
    public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return openAiChatModel.stream(prompt);
    }

    @GetMapping(value = "/chat", produces = "text/html;charset=UTF-8")
    public Flux<String> chat(@RequestParam("msg") String msg) {
        //String call = openAiChatModel.call(msg);
        return openAiChatModel.stream(msg);
        /*return chatClient.prompt()
                .user(msg)
                .stream()
                .content();*/
    }

    /**
     * 调用OpenAI的接口
     *
     * @param msg 我们提的问题
     * @return
     */
    @RequestMapping(value = "/chat2")
    public Object chat2(@RequestParam(value = "msg") String msg) {
        ChatResponse chatResponse = openAiChatModel.call(new Prompt(msg));
        return chatResponse.getResult().getOutput().getContent();
    }

    /**
     * 调用OpenAI的接口
     *
     * @param msg 我们提的问题
     * @return
     */
    @RequestMapping(value = "/chat3")
    public Object chat3(@RequestParam(value = "msg") String msg) {
        //可选参数在配置文件中配置了，在代码中也配置了，那么以代码的配置为准，也就是代码的配置会覆盖掉配置文件中的配置
        ChatResponse chatResponse = openAiChatModel.call(new Prompt(msg, OpenAiChatOptions.builder()
                //.withModel("gpt-4-32k") //gpt的版本，32k是参数量
                .withTemperature(0.4F) //温度越高，回答得比较有创新性，但是准确率会下降，温度越低，回答的准确率会更好
                .build()));
        return chatResponse.getResult().getOutput().getContent();
    }

    /**
     * 调用OpenAI的接口
     *
     * @param msg 我们提的问题
     * @return
     */
    @RequestMapping(value = "/chat4")
    public Object chat4(@RequestParam(value = "msg") String msg) {
        //可选参数在配置文件中配置了，在代码中也配置了，那么以代码的配置为准，也就是代码的配置会覆盖掉配置文件中的配置
        Flux<ChatResponse> flux = openAiChatModel.stream(new Prompt(msg, OpenAiChatOptions.builder()
                //.withModel("gpt-4-32k") //gpt的版本，32k是参数量
                .withTemperature(0.4F) //温度越高，回答得比较有创新性，但是准确率会下降，温度越低，回答的准确率会更好
                .build()));

        flux.toStream().forEach(chatResponse -> {
            System.out.println(chatResponse.getResult().getOutput().getContent());
        });
        return flux.collectList(); //数据的序列，一序列的数据，一个一个的数据返回
    }

    @GetMapping("/prompt")
    public Generation prompt(@RequestParam(value = "adjective") String adjective, @RequestParam(value = "topic") String topic) {
        PromptTemplate promptTemplate = new PromptTemplate("Tell me a {adjective} joke about {topic}");
        Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "topic", topic));
        return openAiChatModel.call(prompt).getResult();
    }

    @GetMapping("/prompt1")
    public List<Generation> prompt1(@RequestParam(value = "name") String name, @RequestParam(value = "voice") String voice) {
        String userText = """
                        Tell me about three famous pirates from the Golden Age of Piracy and why they did.
                        Write at least a sentence for each pirate.
                        """;

        Message userMessage = new UserMessage(userText);

        String systemText = """
                          You are a helpful AI assistant that helps people find information.
                          Your name is {name}
                          You should reply to the user's request with your name and also in the style of a {voice}.
                          """;

        SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
        Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));

        Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

        List<Generation> response = openAiChatModel.call(prompt).getResults();
        return response;
    }

    record ActorsFilms(String actor, List<String> movies) {
    }

    @GetMapping("/structure")
    public ActorsFilms structure() {
        BeanOutputConverter<ActorsFilms> beanOutputConverter = new BeanOutputConverter<>(ActorsFilms.class);
        String format = beanOutputConverter.getFormat();
        String actor = "Tom Hanks";

        String template = """
                            Generate the filmography of 5 movies for {actor}.
                            {format}
                        """;

        Generation generation = openAiChatModel.call(
                new Prompt(new PromptTemplate(template, Map.of("actor", actor, "format", format)).createMessage())).getResult();

        ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());
        return actorsFilms;
    }

    record BusinessPlanCriterion(String description, Integer score) {
    }

    @GetMapping("/structure/pdf")
    public BusinessPlanCriterion structurePDF(@RequestBody String text) {
        BeanOutputConverter<BusinessPlanCriterion> beanOutputConverter = new BeanOutputConverter<>(BusinessPlanCriterion.class);
        String format = beanOutputConverter.getFormat();

        String guide = "Identify your customer and your market. Some of the best companies invent their own markets.";

        String prompt = """
                            This is business plan guide about market potential: {guide}
                            \n This is a startup's business plan content: {text}
                            \n Please summarize the startup's market potential information from the business plan content in Korean, and evaluate the completeness score (0~5)
                            
                            {format}
                        """;

        Generation generation = openAiChatModel.call(
                new Prompt(new PromptTemplate(prompt, Map.of("guide", guide, "text", text, "format", format)).createMessage())).getResult();

        BusinessPlanCriterion businessPlanCriterion = beanOutputConverter.convert(generation.getOutput().getContent());
        return businessPlanCriterion;
    }

    @GetMapping("/structure/bean")
    public Startup analyzePDF(@RequestBody String text) {
        BeanOutputConverter<Startup> beanOutputConverter = new BeanOutputConverter<>(Startup.class);
        String format = beanOutputConverter.getFormat();

        String promptText = """
				This is a startup business plan, please extract the startup fields: name, nationality, funding_amount(Long), last_round, product_name, product_tech, 
				product_market_genres, contact_email, contact_tel, business_purposes_brief, industry_keywords(a string array): {text}
				
				{format}
				""";

        Generation generation = openAiChatModel.call(
                new Prompt(new PromptTemplate(promptText, Map.of("text", text, "format", format)).createMessage())).getResult();

        Startup startup = beanOutputConverter.convert(generation.getOutput().getContent());
        return startup;
    }
}
